//
//  CACarData.m
//  demo
//
//  Created by Seimei on 12-10-16.
//  Copyright (c) 2012年 DEMO. All rights reserved.
//

#import "CACarData.h"

@implementation CACarData
@synthesize odbTimer = _odbTimer,odbSock = _odbSock,obdDisplayStr = _obdDisplayStr;

- (BOOL) connect {
    
    if (!OBD_ENABLE) {
        return FALSE;
    }

    char *p, c;
    char buf[512] = {0};
    int ret;
    
    if (![self connectSocket:&_odbSock host:OBDKEY_HOST port:OBDKEY_PORT]) {
        return FALSE;
    }
    
    send(_odbSock, "ATZ\r", strlen("ATZ\r"), 0);
    
    // wait for the key to send its response back
    // TODO: check for actual response
    sleep(1);
    
    fcntl(_odbSock, F_SETFL, O_NONBLOCK);
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret > 0)
        {
            *(p++) = c;
        }
    } while (ret > 0);
    fcntl(_odbSock, F_SETFL, 0);
    
    memset(buf, 0, 512);
    
    // turn echo off
    send(_odbSock, "ATE0\r", strlen("ATE0\r"), 0);
    
    sleep(1);
    
    fcntl(_odbSock, F_SETFL, O_NONBLOCK);
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret > 0)
        {
            *(p++) = c;
        }
    } while (ret > 0);
    fcntl(_odbSock, F_SETFL, 0);
    
    return TRUE;
}


- (void) readOdbData {
    
    NSLog(@"car readOdbData invoked!\n");

    if (!OBD_ENABLE) {
        return;
    }
    
    char c;
    char buf[512] = {0};
    char *p;
    const char *s;
    NSString *dispStr = @"";
    int ret;
    
    // request the throttle position
    send(_odbSock, "0111\r", 5, 0);
    
    // get the response
    printf("Throttle data:\n");
    
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret <= 0)
        {
            break;
        }
        
        *(p++) = c;
        //pure ascii data output
        putchar(c);
    } while (c != '>');
    
    //make sure p has read data or not
    if (c == '>') {
        p -= 4;
        *p = '\0';
        
        // change pointer to point to begining of data
        p -= 2;
        dispStr = [dispStr stringByAppendingFormat:@"Throttle position: %s\n", p];
    }
    
    
    // request the speed
    send(_odbSock, "010D\r", 5, 0);
    
    // get the response
    printf("Speed data:\n");
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret <= 0)
        {
            break;
        }
        
        *(p++) = c;
        putchar(c);
    } while (c != '>');
    
    if (c == '>') {
        p -= 4;
        *p = '\0';
    
    // change pointer to point to begining of data
        p -= 2;
        dispStr = [dispStr stringByAppendingFormat:@"Speed: %s\n", p];
    }
    
    // request the rpm
    send(_odbSock, "010C\r", 5, 0);
    
    // get the response, note this PID returns 2 bytes so pointer
    // has to be adjusted accordingly
    printf("rpm data:\n");
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret <= 0)
        {
            break;
        }
        
        *(p++) = c;
        putchar(c);
    } while (c != '>');
    
    if (c == '>') {
        p -= 4;
        *p = '\0';
    
    // change pointer to point to begining of data
        p -= 5;
        p[2] = p[3];
        p[3] = p[4];
        p[5] = '\0';
    
        dispStr = [dispStr stringByAppendingFormat:@"RPM: %s\n", p];
    }
    
    // request the engine load
    send(_odbSock, "0104\r", 5, 0);
    
    // get the response
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret <= 0)
        {
            break;
        }
        
        *(p++) = c;
    } while (c != '>');
    
    if (c == '>') {
        p -= 4;
        *p = '\0';
    
    // change pointer to point to begining of data
        p -= 2;
        
        dispStr = [dispStr stringByAppendingFormat:@"Engine Load: %s\n", p];
    }
    
    // request the coolant temp
    send(_odbSock, "0105\r", 5, 0);
    
    // get the response
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret <= 0)
        {
            break;
        }
        
        *(p++) = c;
    } while (c != '>');
    
    if (c == '>') {
        p -= 4;
        *p = '\0';
    
    // change pointer to point to begining of data
        p -= 2;
        
        dispStr = [dispStr stringByAppendingFormat:@"Coolant temp: %s\n", p];
    }
    
    // request the fuel pressure
    send(_odbSock, "010A\r", 5, 0);
    
    // get the response
    p = buf;
    do {
        ret = recv(_odbSock, &c, 1, 0);
        if (ret <= 0)
        {
            break;
        }
        
        *(p++) = c;
    } while (c != '>');
    
    if (c == '>') {
        p -= 4;
        *p = '\0';
    
    // change pointer to point to begining of data
        p -= 2;
        
        dispStr = [dispStr stringByAppendingFormat:@"Fuel Pressure: %s\n", p];
    }
    
    self.obdDisplayStr = [[NSString alloc] initWithFormat
                     :@"%@", dispStr];
    
    NSLog(@"the str: %@", self.obdDisplayStr);
        
}

- (BOOL)connectSocket:(int *)sock host:(NSString *)host port:(NSString *)port {
	int ret;
	struct addrinfo *result, hints;
	struct addrinfo *addr;
    
    //struct timeval tv;
    //fd_set fds;
	
	int tempsock;
	
	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_PASSIVE;
	
	ret = getaddrinfo([host cStringUsingEncoding:(NSStringEncoding)NSASCIIStringEncoding],
                      [port cStringUsingEncoding:(NSStringEncoding)NSASCIIStringEncoding],
                      &hints, &result);
    
	if (ret != 0) return FALSE;
	for(addr = result; addr != NULL; addr = addr->ai_next) {
		if ((tempsock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) == -1) {
			perror("talker: socket");
            NSLog(@"wtf is this");
			continue;
		}
		
		break;
	}
	
	if (tempsock == -1) {
		return FALSE;
	}
	    
	ret = connect(tempsock, addr->ai_addr, addr->ai_addrlen);
       
    if (ret < 0)
    {
        return FALSE;
    }
    
	*sock = tempsock;
	return TRUE;
}



@end
